package pl.kosmowska.ewelina.server.dao;

import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.Transaction;

import pl.kosmowska.ewelina.server.jdo.LoanData;
import pl.kosmowska.ewelina.server.jdo.OutcomeData;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

public class LoanDataDAO extends JdoDAOImpl<LoanData> {

	private static final Logger log = Logger.getLogger(LoanDataDAO.class
			.getName());

	public LoanData findLoanData(String id) {
		Long uid = UserDataDAO.getLoggedInUserId();
		if (id == null) {
			return null;
		}

		List<OutcomeData> paidOutcomeList = null;
		paidOutcomeList = getPaidOutcomeList(id, new Date());

		Key key = KeyFactory.stringToKey(id);
		PersistenceManager pm = getPersistenceManager();
		try {
			LoanData loanData = pm.getObjectById(LoanData.class, key);
			if (loanData.getUserId() != uid) { // does the uid really own this
				// Loan
				loanData = null;
			}
			updatePaymentStatus(paidOutcomeList, loanData);
			return loanData;
		} catch (Exception e) {
			log.log(Level.SEVERE, "Error: LoanData.findLoanData(id): id=" + id,
					e);
			e.printStackTrace();
		} finally {
			pm.close();
		}
		return null;
	}

	private void updatePaymentStatus(List<OutcomeData> paidOutcomeList,
			LoanData loanData) {
		if ((paidOutcomeList == null) || (paidOutcomeList.isEmpty())) {
			loanData.setValuePaid(0);
			loanData.setValueNotPaid(loanData.getValueToPay());
		} else {
			loanData.setValuePaid(-countPaidSum(paidOutcomeList));
			loanData.setValueNotPaid(loanData.getValueToPay()
					- loanData.getValuePaid());
		}

	}

	private float countPaidSum(List<OutcomeData> paidOutcomeList) {
		float sum = 0;
		for (OutcomeData data : paidOutcomeList) {
			sum += data.getValue();
		}
		return sum;
	}

	public List<LoanData> findLoanDataByUser() {
		Long uid = UserDataDAO.getLoggedInUserId();

		String qfilter = "userId==" + uid + "";

		PersistenceManager pm = getPersistenceManager();
		try {
			javax.jdo.Query query = pm.newQuery("select from "
					+ LoanData.class.getName());
			query.setFilter(qfilter);
			List<LoanData> list = (List<LoanData>) query.execute();

			for (LoanData loanData : list) {
				List<OutcomeData> paidOutcomeList = null;
				paidOutcomeList = getPaidOutcomeList(loanData.getId(),
						new Date());
				updatePaymentStatus(paidOutcomeList, loanData);
			}

			List<LoanData> r = (List<LoanData>) pm.detachCopyAll(list);

			return r;
		} catch (Exception e) {
			log.log(Level.SEVERE,
					"Error: LoanData.findLoanDataByUser(): qfilter=" + qfilter,
					e);
		} finally {
			pm.close();
		}
		return null;
	}

	public LoanData persist(LoanData loanData) {
		return (LoanData) persistEntity(loanData);
	}

	public LoanData persist(LoanData loanData, List<OutcomeData> outcomeList) {

		Long uid = UserDataDAO.getLoggedInUserId();
		List<OutcomeData> previousOutcomeList = null;
		PersistenceManager pm = getPersistenceManager();
		if (loanData.getVersion()!=null && loanData.getVersion()>0) {
			previousOutcomeList = getCurrentOutcomeList(loanData.getId(), pm);
			if ((previousOutcomeList == null)
					|| (previousOutcomeList.isEmpty())) {
				log.severe("LoanData.persist() Error: Something weird going on getting previous list. Empty list");
				return null;
			}

		}

		if (loanData.getVersion() == null) {
			loanData.setVersion(01l);
		}
		loanData.setVersion(loanData.getVersion()+1);
		Iterator<OutcomeData> newListItr = outcomeList.iterator();
		try {

			loanData.setUserId(uid);
			pm.makePersistent(loanData);

			while (newListItr.hasNext()) {
				OutcomeData tmp = newListItr.next();
				tmp.setUserId(uid);
				tmp.setVersion(01L);
				tmp.setGroupKey(loanData.getId());
			}
			pm.makePersistentAll(outcomeList);
			if (previousOutcomeList != null)
				pm.deletePersistentAll(previousOutcomeList);

		} catch (Exception e) {
			log.log(Level.SEVERE, "Error: LoanData.persist(): this=" + this, e);
			e.printStackTrace();
		} finally {
			pm.close();
		}
		return loanData;
	}

	private List<OutcomeData> getCurrentOutcomeList(String id,
			PersistenceManager pm) {
		try {
			final javax.jdo.Query query = pm.newQuery("SELECT FROM "
					+ OutcomeData.class.getName()
					+ " WHERE this.groupKey == groupId "
					+ " PARAMETERS String groupId ");

			List<OutcomeData> list = (List<OutcomeData>) query.execute(id);

			if ((list == null) || (list.isEmpty())) {
				log.severe("LoanData.getCurrentOutcomeList() Error: Empty list returned, wrong query?");
				return null;
			}

			return list;
		} catch (Exception e) {
			log.log(Level.SEVERE,
					"Error: LoanData.findOutcomeDataByUser()", e);
		} 
		return null;

	}

	private void deleteCurrentOutcomeList(String id, PersistenceManager pm) {
		try {
			final javax.jdo.Query query = pm.newQuery("SELECT FROM "
					+ OutcomeData.class.getName()
					+ " WHERE this.groupKey == groupId "
					+ " PARAMETERS String groupId ");

			query.deletePersistentAll(id);

		} catch (Exception e) {
			log.log(Level.SEVERE,
					"Error: LoanData.findOutcomeDataByUser()", e);
		} 

	}

	private List<OutcomeData> getPaidOutcomeList(String id, Date date) {
		Date queryStartDate = getDate(date);
		PersistenceManager pm = getPersistenceManager();
		try {
			final javax.jdo.Query query = pm
					.newQuery("SELECT FROM "
							+ OutcomeData.class.getName()
							+ " WHERE this.groupKey == groupId && this.date <= queryStartDate "
							+ " PARAMETERS String groupId, java.util.Date queryStartDate,");

			List<OutcomeData> list = (List<OutcomeData>) query.execute(id,
					queryStartDate);

			if ((list == null) || (list.isEmpty())) {
				log.severe("LoanData.getPaidOutcomeList() Error: Empty list returned, wrong query?");
				return null;
			}

			return list;
		} catch (Exception e) {
			log.log(Level.SEVERE,
					"Error: LoanData.findOutcomeDataByUser()", e);
			e.printStackTrace();
		} finally {
			pm.close();
		}
		return null;

	}

	private Date getDate(Date date) {
		java.util.Calendar calendar = Calendar.getInstance();
		calendar.clear();
		calendar.set(date.getYear() + 1900, date.getMonth(), date.getDate());
		return calendar.getTime();
	}

	public Boolean deleteLoanData(String id) {

		if (id == null) {
			return false;
		}
		PersistenceManager pm = getPersistenceManager();
		List<OutcomeData> currentOutcomeList = null;
		deleteCurrentOutcomeList(id, pm);

		Long uid = UserDataDAO.getLoggedInUserId();
		Key key = KeyFactory.stringToKey(id);
		Transaction tx = pm.currentTransaction();
		try {
			LoanData e = pm.getObjectById(LoanData.class, key);
			pm.deletePersistent(e);
			return true;
		} catch (Exception e) {
			log.log(Level.SEVERE, "Error:", e);
		} finally {
			pm.close();
		}

		return false;
	}

}